package com.sdkj.controller.activiti;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sdkj.controller.base.BaseController;
import com.sdkj.entity.Page;
import com.sdkj.util.Const;
import com.sdkj.util.PageData;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * 流程模型相关Controller
 * @author leiweiping
 * @version 2015-05-17
 */
@Controller
@RequestMapping(value = "/actmodel")
public class ActModelController extends BaseController {

	String menuUrl = "actmodel/list.do"; //菜单地址(权限用)
	@Resource
	private RepositoryService repositoryService;
	
	private ObjectMapper objectMapper = new ObjectMapper();
	
	/**
	 * 流程模型列表
	 */
	@RequestMapping(value="/list")
	public ModelAndView list(Page page) {
		ModelAndView mv = this.getModelAndView();
		PageData pd = new PageData();
		try{
			pd = this.getPageData();
			String category = pd.getString("category");
			page.setPd(pd);
			ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion().orderByLastUpdateTime().desc();
			if (StringUtils.isNotEmpty(category)){
				modelQuery.modelCategory(category);
			}
			List<Model>	varList = modelQuery.list();
			mv.setViewName("activiti/model/model_list");
			mv.addObject("varList", varList);
			mv.addObject("pd", pd);
			mv.addObject(Const.SESSION_QX,this.getHC());	//按钮权限
		} catch(Exception e){
			logger.error(e.toString(), e);
		}
		return mv;
	}
	

	/**
	 * 跳转新增流程模型页面
	 */
	@RequestMapping(value = "/goAdd")
	public ModelAndView goAdd() {
		logBefore(logger, "去新增流程模型页面");
		ModelAndView mv = this.getModelAndView();
		PageData pd = new PageData();
		pd = this.getPageData();
		try {
			mv.setViewName("activiti/model/model_create");
			mv.addObject("pd", pd);
		} catch (Exception e) {
			logger.error(e.toString(), e);
		}						
		return mv;
	}
	
	/**
	 * 创建模型
	 * @return 
	 */
	@RequestMapping(value = "/save")
	public void save(HttpServletRequest request,HttpServletResponse response) throws Exception{
			logBefore(logger, "新增流程模型");
			JSONObject json = new JSONObject();
			try{
				//封装视图流程图空间
				ObjectNode editorNode = objectMapper.createObjectNode();
				editorNode.put("id", "canvas");
				editorNode.put("resourceId", "canvas");
				ObjectNode properties = objectMapper.createObjectNode();
				properties.put("process_author", "zsy");
				editorNode.put("properties", properties);
				ObjectNode stencilset = objectMapper.createObjectNode();
				stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
				editorNode.put("stencilset", stencilset);
				
				//封装流程模型实体
				String description = request.getParameter("description");
				String key = request.getParameter("key");
				String name = request.getParameter("name");
				String category = request.getParameter("category");
				Model modelData = repositoryService.newModel();
				description = StringUtils.defaultString(description);
				modelData.setKey(StringUtils.defaultString(key));
				modelData.setName(name);
				modelData.setCategory(category);
				modelData.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count()+1)));
	
				//封装modelObjectNode数据格式
				ObjectNode modelObjectNode = objectMapper.createObjectNode();
				modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
				modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
				modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
				modelData.setMetaInfo(modelObjectNode.toString());
				
				//添加入库流程模块数据
				repositoryService.saveModel(modelData);
				repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
				json.put("status", true);
				json.put("message", "创建模型成功!");
				json.put("modelid", modelData.getId());
			}catch(Exception e){
				e.printStackTrace();
				json.put("status", false);
				json.put("message", "创建模型失败!");
				json.put("modelid", "0");
			}
			
			response.setCharacterEncoding("utf-8");
			PrintWriter out = response.getWriter();
			out.write(json.toString());
			out.flush();
			out.close();
	}

	/**
	 * 根据Model部署流程
	 * @throws IOException 
	 */
	@RequestMapping(value = "/deploy")
	public void deploy(String id,HttpServletResponse response) throws IOException {
		String message = "";
		try {
			Model modelData = repositoryService.getModel(id);
			BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
			BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
			BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
			byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
			
			String processName = modelData.getName();
			if (!StringUtils.endsWith(processName, ".bpmn20.xml")){
				processName += ".bpmn20.xml";
			}
			ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
			Deployment deployment = repositoryService.createDeployment().name(modelData.getName())
					.addInputStream(processName, in).deploy();
			
			// 设置流程分类
			List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
			for (ProcessDefinition processDefinition : list) {
				repositoryService.setProcessDefinitionCategory(processDefinition.getId(), modelData.getCategory());
				message = "部署成功，流程ID=" + processDefinition.getId();
			}
			if (list.size() == 0){
				message = "部署失败，没有流程。";
			}
		} catch (Exception e) {
			e.printStackTrace();
			message = "设计模型图不正确，检查模型正确性，模型ID="+id;
		}
		response.setCharacterEncoding("utf-8");
		PrintWriter out = response.getWriter();
		out.write(message);
		out.flush();
		out.close();
	}
	
	/**
	 * 导出model的xml文件
	 */
	@ModelAttribute
	@RequestMapping(value = "/export")
	public void export(HttpServletRequest request, HttpServletResponse response) {
		String id = request.getParameter("id");
		try {
			Model modelData = repositoryService.getModel(id);
			BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
			BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
			BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
			byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);

			ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
			IOUtils.copy(in, response.getOutputStream());
			String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
			response.setHeader("Content-Disposition", "attachment; filename=" + filename);
			response.flushBuffer();
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("导出model的xml文件失败，模型ID="+id);
		}
	}

	/**
	 * 更新Model分类
	 */
	@RequestMapping(value = "updateCategory")
	public String updateCategory(String id, String category) {
		Model modelData = repositoryService.getModel(id);
		modelData.setCategory(category);
		repositoryService.saveModel(modelData);
		String message = "设置成功，模块ID=" + id;
		return message;
	}
	
	/**
	 * 删除Model
	 * @param id
	 * @param redirectAttributes
	 * @return
	 */
	@RequestMapping(value = "/delete")
	public void delete(String id, HttpServletResponse response) {
		repositoryService.deleteModel(id);
		String message = "删除成功，模型ID=" + id;
		try{
			response.setCharacterEncoding("utf-8");
			PrintWriter out = response.getWriter();
			out.write(message);
			out.flush();
			out.close();
		} catch(Exception e){
			logger.error(e.toString(), e);
		}
	}
	
	/* ===============================权限================================== */
	public Map<String, String> getHC(){
		Subject currentUser = SecurityUtils.getSubject();  //shiro管理的session
		Session session = currentUser.getSession();
		return (Map<String, String>)session.getAttribute(Const.SESSION_QX);
	}
	/* ===============================权限================================== */
	
	@InitBinder
	public void initBinder(WebDataBinder binder){
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(format,true));
	}
}
